﻿#include "ParallelLineGraphicsItem.h"
#include "GraphicsDef.h"
#include <QGraphicsScene>
#include <QGraphicsSceneMouseEvent>
#include <QPainter>
#include <QFocusEvent>

namespace OfUI {

	ParallelLineGraphicsItem::ParallelLineGraphicsItem(QGraphicsItem *parent)
		: BaseGraphicsItem(parent)
		, m_bAdding(true)
		, m_eSelType(SELECT_NONE)
	{
		setType(ItemType::PARALLEL_LINE);
	}

	ParallelLineGraphicsItem::~ParallelLineGraphicsItem()
	{
	}

	void ParallelLineGraphicsItem::setParallelLine(const QLineF& firstLine, const QLineF& secondLine)
	{
		prepareGeometryChange();
		m_firstLine = firstLine;
		m_secondLine = secondLine;

		// 求得垂直线中间点，根据中间点求得垂直线分别与两条线的交点
		QPointF verticalLineCenter = (m_firstLine.p1() + m_secondLine.p2()) / 2;
		QPointF verticalP1 = getPointVerticalToLine(verticalLineCenter, m_firstLine);
		QPointF verticalP2 = getPointVerticalToLine(verticalLineCenter, m_secondLine);
		m_verticalLine = QLineF(verticalP1, verticalP2);

		emit signalDataChanged();
	}

	QLineF ParallelLineGraphicsItem::getFirstLine() const
	{
		return m_firstLine;
	}

	QLineF ParallelLineGraphicsItem::getSecondLine() const
	{
		return m_secondLine;
	}

	QLineF ParallelLineGraphicsItem::getVerticalLine() const
	{
		return m_verticalLine;
	}

	bool ParallelLineGraphicsItem::isAdding() const
	{
		return m_bAdding;
	}

	bool ParallelLineGraphicsItem::isEditing() const
	{
		return SELECT_NONE != m_eSelType;
	}

	bool ParallelLineGraphicsItem::isVaild() const
	{
		if (m_firstLine.length() > 1e-6 &&
			m_secondLine.length() > 1e-6 &&
			m_verticalLine.length() > 1e-6)
		{
			return true;
		}
		else
		{
			return false;
		}
	}

	BaseGraphicsItem::MouseDragType ParallelLineGraphicsItem::select(const QPointF& point, int* selType /*= nullptr*/) const
	{
		MouseDragType eDragType = DRAG_NONE;
		SelectType eSelectType = SELECT_NONE;

		double dDistance = 5 / getViewScale();
		if (QLineF(m_secondLine.p2(), point).length() <= dDistance)
		{
			eDragType = DRAG_EDIT;
			eSelectType = SELECT_SECOND_LINE_P2;
		}
		else if (QLineF(m_secondLine.p1(), point).length() <= dDistance)
		{
			eDragType = DRAG_EDIT;
			eSelectType = SELECT_SECOND_LINE_P1;
		}
		else if (QLineF(m_secondLine.center(), point).length() <= dDistance)
		{
			eDragType = DRAG_EDIT;
			eSelectType = SELECT_SECOND_LINE;
		}
		else if (QLineF(m_firstLine.p2(), point).length() <= dDistance)
		{
			eDragType = DRAG_EDIT;
			eSelectType = SELECT_FIRST_LINE_P2;
		}
		else if (QLineF(m_firstLine.p1(), point).length() <= dDistance)
		{
			eDragType = DRAG_EDIT;
			eSelectType = SELECT_FIRST_LINE_P1;
		}
		else if (QLineF(m_firstLine.center(), point).length() <= dDistance)
		{
			eDragType = DRAG_EDIT;
			eSelectType = SELECT_FIRST_LINE;
		}
		else
		{
			if ((!m_firstLine.isNull() && distanceFromPointToLine(point, m_secondLine) <= dDistance) ||
				(!m_secondLine.isNull() && distanceFromPointToLine(point, m_firstLine) <= dDistance))
			{
				eDragType = DRAG_EDIT;
				eSelectType = SELECT_ALL;
			}
		}

		if (selType)
		{
			*selType = eSelectType;
		}
		return eDragType;
	}

	void ParallelLineGraphicsItem::cursor(const QPointF& point, QCursor& cursor) const
	{
		int nType;
		if (BaseGraphicsItem::DRAG_NONE != select(point, &nType))
		{
			switch (nType)
			{
			case SELECT_FIRST_LINE:
			case SELECT_FIRST_LINE_P1:
			case SELECT_FIRST_LINE_P2:
			case SELECT_SECOND_LINE:
			case SELECT_SECOND_LINE_P1:
			case SELECT_SECOND_LINE_P2:
				cursor = Qt::PointingHandCursor;
				break;
			case SELECT_ALL:
				cursor = Qt::SizeAllCursor;
				break;
			default:
				break;
			}
		}
	}

	void ParallelLineGraphicsItem::mousePressEvent(QGraphicsSceneMouseEvent *event)
	{
		if (Qt::LeftButton == event->button())
		{
			m_pressMousePos = event->scenePos();

			if (isAdding())
			{
				if (SELECT_NONE == m_eSelType)
				{
					QLineF line(m_pressMousePos, m_pressMousePos);
					setParallelLine(line, line);
					m_eSelType = SELECT_FIRST_LINE_P2;
					return;
				}
			}
			else
			{
				int nType = SELECT_NONE;
				if (BaseGraphicsItem::DRAG_NONE != select(m_pressMousePos, &nType))
				{
					m_eSelType = static_cast<SelectType>(nType);
					return;
				}
			}
		}
		QFocusEvent focusEvent(QEvent::FocusOut, Qt::OtherFocusReason);
		focusOutEvent(&focusEvent);
	}

	void ParallelLineGraphicsItem::mouseReleaseEvent(QGraphicsSceneMouseEvent *event)
	{
		if (Qt::LeftButton == event->button())
		{
			if (isAdding() && SELECT_FIRST_LINE_P2 == m_eSelType)
			{
				m_eSelType = SELECT_SECOND_LINE;
				return;
			}
		}
		QFocusEvent focusEvent(QEvent::FocusOut, Qt::OtherFocusReason);
		focusOutEvent(&focusEvent);
	}

	void ParallelLineGraphicsItem::mouseMoveEvent(QGraphicsSceneMouseEvent *event)
	{
		if (SELECT_NONE == m_eSelType)
			return;

		QPointF mousePos = event->scenePos();
		QRectF sceneRect = scene()->sceneRect();
		// 保证鼠标在场景内
		mousePos.setX(qMin(mousePos.rx(), sceneRect.right()));
		mousePos.setY(qMin(mousePos.ry(), sceneRect.bottom()));
		mousePos.setX(qMax(mousePos.rx(), sceneRect.left()));
		mousePos.setY(qMax(mousePos.ry(), sceneRect.top()));

		QLineF firstLine = m_firstLine;
		QLineF secondLine = m_secondLine;

		if (SELECT_FIRST_LINE == m_eSelType)
		{
			firstLine.translate(mousePos - firstLine.center());
		}
		else if (SELECT_FIRST_LINE_P1 == m_eSelType)
		{
			if (Qt::ShiftModifier & event->modifiers())
			{
				QLineF line = getStraightLineFromObliqueLine(QLineF(firstLine.p2(), mousePos));
				firstLine.setP1(line.p2());
			}
			else
			{
				firstLine.setP1(mousePos);
			}
			secondLine.setP1(secondLine.p2() - (firstLine.p2() - firstLine.p1()));
		}
		else if (SELECT_FIRST_LINE_P2 == m_eSelType)
		{
			firstLine.setP2(mousePos);
			if (Qt::ShiftModifier & event->modifiers())
			{
				firstLine = getStraightLineFromObliqueLine(firstLine);
			}
			secondLine.setP2(secondLine.p1() + firstLine.p2() - firstLine.p1());
		}
		else if (SELECT_SECOND_LINE == m_eSelType)
		{
			secondLine.translate(mousePos - secondLine.center());
		}
		else if (SELECT_SECOND_LINE_P1 == m_eSelType)
		{
			if (Qt::ShiftModifier & event->modifiers())
			{
				QLineF line = getStraightLineFromObliqueLine(QLineF(secondLine.p2(), mousePos));
				secondLine.setP1(line.p2());
			}
			else
			{
				secondLine.setP1(mousePos);
			}
			firstLine.setP1(firstLine.p2() - (secondLine.p2() - secondLine.p1()));
		}
		else if (SELECT_SECOND_LINE_P2 == m_eSelType)
		{
			secondLine.setP2(mousePos);
			if (Qt::ShiftModifier & event->modifiers())
			{
				secondLine = getStraightLineFromObliqueLine(secondLine);
			}
			firstLine.setP2(firstLine.p1() + secondLine.p2() - secondLine.p1());
		}
		else if (SELECT_ALL == m_eSelType)
		{
			QPointF offsetPoint = mousePos - m_pressMousePos;
			firstLine.translate(offsetPoint);
			secondLine.translate(offsetPoint);
			m_pressMousePos = mousePos;
		}
		setParallelLine(firstLine, secondLine);
	}

	void ParallelLineGraphicsItem::focusOutEvent(QFocusEvent *event)
	{
		Q_UNUSED(event);
		if (isAdding())
		{
			emit signalAddFinished();
			m_bAdding = false;
		}
		m_eSelType = SELECT_NONE;
	}

	QRectF ParallelLineGraphicsItem::boundingRect() const
	{
		QPainterPath path;
		QPolygonF polygon;

		polygon.append(m_firstLine.p1());
		polygon.append(m_firstLine.p2());
		polygon.append(m_secondLine.p1());
		polygon.append(m_secondLine.p2());
		polygon.append(m_verticalLine.p1());
		polygon.append(m_verticalLine.p2());
		path.addPolygon(polygon);

		double dRadius = 2 / getViewScale();
		path.addEllipse(m_firstLine.center(), dRadius, dRadius);
		path.addEllipse(m_firstLine.p1(), dRadius, dRadius);
		path.addEllipse(m_firstLine.p2(), dRadius, dRadius);
		path.addEllipse(m_secondLine.center(), dRadius, dRadius);
		path.addEllipse(m_secondLine.p1(), dRadius, dRadius);
		path.addEllipse(m_secondLine.p2(), dRadius, dRadius);

		QRectF rectF = path.controlPointRect().adjusted(-5, -5, 5, 5);
		return rectF;
	}

	void ParallelLineGraphicsItem::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget /* = nullptr */)
	{
		Q_UNUSED(option);
		Q_UNUSED(widget);

		if (this->scene())
		{
			painter->save();
			painter->setRenderHint(QPainter::Antialiasing);

			// 通过反向缩放painter实现矢量绘制效果
			double dViewScale = getViewScale();
			painter->scale(1 / dViewScale, 1 / dViewScale);

			// painter缩小，则绘制坐标放大，保证显示位置不变
			QLineF firstLine = QLineF(m_firstLine.p1() * dViewScale, m_firstLine.p2() * dViewScale);
			QLineF secondLine = QLineF(m_secondLine.p1() * dViewScale, m_secondLine.p2() * dViewScale);
			QLineF verticalLine = QLineF(m_verticalLine.p1() * dViewScale, m_verticalLine.p2() * dViewScale);

			// 绘制平行线
			QPen statePen = getPen(getState());
			QPen dotLinePen = getPen(getState());
			dotLinePen.setStyle(Qt::DotLine);

			painter->setPen(dotLinePen);
			painter->drawLine(firstLine.center(), verticalLine.p1());
			painter->drawLine(verticalLine);
			painter->drawLine(secondLine.center(), verticalLine.p2());
			painter->setPen(statePen);
			painter->drawLine(firstLine);
			painter->drawLine(secondLine);

			// 绘制拖拽点
			if (STATE_SELECT == getState())
			{
				double dRadius = 2;
				painter->drawEllipse(firstLine.center(), dRadius, dRadius);
				painter->drawEllipse(firstLine.p1(), dRadius, dRadius);
				painter->drawEllipse(firstLine.p2(), dRadius, dRadius);
				painter->drawEllipse(secondLine.center(), dRadius, dRadius);
				painter->drawEllipse(secondLine.p1(), dRadius, dRadius);
				painter->drawEllipse(secondLine.p2(), dRadius, dRadius);
			}
			painter->restore();
		}
	}

}